package org.simple.wechat.demo.utils;

/***
 * @author gaoqijin
 * @date 2020-9-10
 * @Description
 */
import org.simple.wechat.demo.ienum.IEnum;
import org.simple.wechat.demo.ienum.IEnumAnnotation;
import org.simple.wechat.demo.ienum.IEunmException;

import javax.validation.constraints.NotNull;
import java.util.Arrays;
import java.util.Optional;
import java.util.function.Predicate;

/***
 * @author gaoqijin
 * @date 2020-8-14
 * @Description
 */
public class IEnumUtils {
  private IEnumUtils(){}


  private final static String NOT_FIND_ENUM ="找不到对应的枚举类信息";

  /**
   * 通过名称
   * @param name
   * @param clazz
   * @param <T>
   * @return
   */
  public static <T extends IEnum> T getEnumByName(@NotNull String name,@NotNull Class<T> clazz){
    return getEnumByPredicate(iEnum->iEnum.getName().equalsIgnoreCase(name),clazz,true);
  }
  public static <T extends IEnum> T getEnumByName(@NotNull String name,@NotNull Class<T> clazz,boolean exception){
    return getEnumByPredicate(iEnum->iEnum.getName().equalsIgnoreCase(name),clazz,exception);
  }
  public static <T extends IEnum> T getEnumByName(@NotNull String name,@NotNull Class<T> clazz,T defaultEnum){
    return getEnumByPredicate(iEnum->iEnum.getName().equalsIgnoreCase(name),clazz,defaultEnum);
  }
  /**
   * 通过名称
   * @param code
   * @param clazz
   * @param <T>
   * @return
   */
  public static <T extends IEnum> T getEnumByCode(@NotNull String code,@NotNull Class<T> clazz){
    return getEnumByPredicate(iEnum->String.valueOf(iEnum.getCode()).equalsIgnoreCase(code),clazz,true);
  }
  public static <T extends IEnum> T getEnumByCode(@NotNull Integer code,@NotNull Class<T> clazz){
    return getEnumByPredicate(iEnum->String.valueOf(iEnum.getCode()).equalsIgnoreCase(String.valueOf(code)),clazz,true);
  }
  public static <T extends IEnum> T getEnumByCode(@NotNull Short code,@NotNull Class<T> clazz){
    return getEnumByPredicate(iEnum->String.valueOf(iEnum.getCode()).equalsIgnoreCase(String.valueOf(code)),clazz,true);
  }
  public static <T extends IEnum> T getEnumByCode(@NotNull String code,@NotNull Class<T> clazz,boolean exception){
    return getEnumByPredicate(iEnum->String.valueOf(iEnum.getCode()).equalsIgnoreCase(code),clazz,exception);
  }
  public static <T extends IEnum> T getEnumByCode(@NotNull Short code,@NotNull Class<T> clazz,boolean exception){
    return getEnumByPredicate(iEnum->String.valueOf(iEnum.getCode()).equalsIgnoreCase(String.valueOf(code)),clazz,exception);
  }

  /**
   * 返回描述
   */
  public static <T extends IEnum>  String getEnumDescByName(@NotNull String name,@NotNull Class<T> clazz){
    return getEnumByName(name, clazz).getDesc();
  }
  public static <T extends IEnum>  String getEnumDescByCode(@NotNull String code,@NotNull Class<T> clazz){
    return getEnumByCode(code, clazz).getDesc();
  }
  public static <T extends IEnum>  String getEnumDescByCode(@NotNull Short code,@NotNull Class<T> clazz){
    return getEnumByCode(code, clazz).getDesc();
  }


  /**
   * 通过最终执行的方法
   * @param predicate
   * @param clazz
   * @param <T>
   * @return
   */
  public static <T extends IEnum> T getEnumByPredicate(@NotNull Predicate<T> predicate,@NotNull Class<T> clazz){
    return getEnumByPredicate(predicate,clazz,true);
  }
  public static <T extends IEnum> T getEnumByPredicate(@NotNull Predicate<T> predicate,@NotNull Class<T> clazz,boolean exception){
    return getEnumByPredicate(predicate,clazz,exception,null);
  }
  public static <T extends IEnum> T getEnumByPredicate(@NotNull Predicate<T> predicate,@NotNull Class<T> clazz,T defaultEnum){
    return getEnumByPredicate(predicate,clazz,false,defaultEnum);
  }
  private static <T extends IEnum> T getEnumByPredicate(@NotNull Predicate<T> predicate,@NotNull Class<T> clazz,boolean exception,T defaultEnum){
    T[] enumConstants = clazz.getEnumConstants();
    Optional<T> optionalT =
        Arrays.stream(enumConstants).filter(predicate).findFirst();
    if (optionalT.isPresent()) {
      return optionalT.get();
    }else if (null != defaultEnum){
      return defaultEnum;
    }else{
      T t = Arrays.stream(enumConstants).filter(iEnumT -> {
        try {
          return iEnumT.getClass().getField(iEnumT.getName())
              .getAnnotation(IEnumAnnotation.DefaultEnum.class) != null;
        }catch (NoSuchFieldException e){
          return false;
        }
      }).findFirst().orElse(null);
      if(t == null && exception){
        IEnumAnnotation.NotFoundMsg annotation =
            clazz.getAnnotation(IEnumAnnotation.NotFoundMsg.class);
        if(annotation != null){
          throw new IEunmException(annotation.value());
        }else{
          throw new IEunmException(NOT_FIND_ENUM);
        }
      }
      return t;
    }
  }

}

